
#include <stdarg.h>
#include <string.h>
#include "DebugDisplay.h"


#define VID_MEMORY 0xB8000 
/*0xB8000 is the pointer address to the Color Text Mode
and since we are still in text mode we use 0xB8000.
Also note that this memory size is 4000 or 4800, if i remember correctly thus (80 x 25 x 2)
or (80 x 30 x 2)
*/
						   

//This forms the basis of our bounding rect
//All text following GotoXY will be repositioned accordingly
static unsigned int xPos = 0, yPos = 0;
static unsigned startX = 0, startY = 0;

//Standard color
static unsigned color = 0;

#ifdef _MSC_VER
#pragma warning (disable:4244) //disable warnings for casting...i think
#endif

//All printing methods will work through this method to print
void DebugPutc (unsigned char c) {
	if (c == 0)
		return;

	if (c == '\n'||c=='\r') {	//start with new line
		yPos += 2;
		xPos = startX;
		return;
	}

	if (xPos > 79) { //if we reach end of screen, start with new line		
		yPos += 2;
		xPos = startX;
		return;
	}

	//draw the character 
	unsigned char* p = (unsigned char*)VID_MEMORY + (xPos++)*2 + yPos * 80;  //multiply xpos by 2 cause one character uses 2bytes
	/*	set pointer to address and region to use for printing..so that we dont print 
		letters over each other...or out of bounds..if i understand correctly
	*/

	/*	Ok to print a character we just need to write to bytes to the video memory,
		the first byte specifies the character and the second, byte specifies the attributes
	*/
	*p++ = c; //specify character to print
	*p = color; //specify attributes (in our case the color)
}

char tbuf[32]; //each character takes 2bytes so if we use 16 charactes, see below then we need size of 32
char bchars[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; //characters for hex, if im right

void itoa(unsigned i,unsigned base,char* buf) {
   int pos = 0;
   int opos = 0;
   int top = 0;

   if (i == 0 || base > 16) {
      buf[0] = '0';
      buf[1] = '\0';
      return;
   }

   while (i != 0) {
      tbuf[pos] = bchars[i % base];
      pos++;
      i /= base;
   }
   top=pos--;
   for (opos=0; opos<top; pos--,opos++) {
      buf[opos] = tbuf[pos];
   }
   buf[opos] = 0;
}

void itoa_s(int i,unsigned base,char* buf) {
   if (base > 16) return;
   if (i < 0) {
      *buf++ = '-';
      i *= -1;
   }
   itoa(i,base,buf);
}

//Interface Functions 

//set color that we use in our text mode 
unsigned DebugSetColor (const unsigned col)
{
	unsigned t = color; //save previous color
	color = col; //set new color
	return t; //return previous color
}


void DebugClrScr(const unsigned short clr)
{
	unsigned char* p = (unsigned char*)VID_MEMORY;

	for (int i = 0; i < 160*30; i+=2)
	/*	160*30 specifies that we want to clear entire video memory.
		Remember in beginning i said memory size may be 4800bytes...
		thus (80 * 2 * 30)..see the 160 is the 80 * 2 
		and also note we increase by 2 each time cause each character takes 2bytes.
	*/
	{
		p[i] = ' '; //character to print
		p[i+1] = clr;
	}

	xPos = startX; //reset pointer to beginning
	yPos = startY;
}



void DebugGotoXY (unsigned x, unsigned y) {

	// reposition starting vectors for next text to follow
	// multiply by 2 due to the video modes 2byte per character layout
	xPos = x*2;
	yPos = y*2;
	startX = xPos;
	startY = yPos;
}

//Print a string of characters to screen
void DebugPuts (char* str) {

	if (!str)
		return;

	for (size_t i=0; i<strlen (str); i++) //print each character in string to screen
		DebugPutc (str[i]);
}

int DebugPrintf (const char* str, ...) {

	if(!str)
		return 0;

	va_list		args;
	va_start (args, str);

	for (size_t i=0; i<strlen(str);i++) {

		switch (str[i]) { //check for formating options

			case '%':

				switch (str[i+1]) {
				/*I think this explains itself pretty clear, 
					if you ever used c or c++ you will understand what happens hear*/
					/*** characters ***/
					case 'c': { 
						char c = va_arg (args, char);
						DebugPutc (c);
						i++;		// go to next character
						break;
					}

					/*** address of ***/
					case 's': {
						int c = (int&) va_arg (args, char);
						char str[32]={0};
						itoa_s (c, 16, str);
						DebugPuts (str);
						i++;		// go to next character
						break;
					}

					/*** integers ***/
					case 'd':
					case 'i': {
						int c = va_arg (args, int);
						char str[32]={0};
						itoa_s (c, 10, str);
						DebugPuts (str);
						i++;		// go to next character
						break;
					}

					/*** display in hex ***/
					case 'X':
					case 'x': {
						int c = va_arg (args, int);
						char str[32]={0};
						itoa_s (c,16,str);
						DebugPuts (str);
						i++;		// go to next character
						break;
					}

					default:
						va_end (args);
						return 1;
				}

				break;

			default:
				DebugPutc (str[i]); //if no formatting then just print character found
				break;
		}

	}

	va_end (args);
}



